#ifndef ARC_LRU_PART_HPP
#define ARC_LRU_PART_HPP

#include <unordered_map>
#include <mutex>

#include "./ArcNode.hpp"

namespace CachePool
{
    template <typename Key, typename Value>
    class ArcLruPart
    {
    public:
        using NodeType = ArcNode<Key, Value>;
        using NodePtr = std::shared_ptr<NodeType>;
        using NodeMap = std::unordered_map<Key, NodePtr>;

        ArcLruPart(const size_t capacity, const size_t transformThreshold)
            : capacity_(capacity), ghostCapacity_(capacity), transformThreshold_(transformThreshold)
        {
            this->initNodeLists();
        }

        bool set(const Key &key, const Value &value)
        {
            if (this->capacity_ <= 0)
            {
                return false;
            }

            std::lock_guard<std::mutex> lock(this->mutex_);

            auto it = this->mainNodeMap_.find(key);
            if (it == this->mainNodeMap_.end())
            {
                return this->addMainNode(key, value);
            }

            return modMainNode(it->second, value);
        }

        bool get(const Key &key, Value &value, bool &shouldTransform)
        {
            std::lock_guard<std::mutex> lock(this->mutex_);

            auto it = this->mainNodeMap_.find(key);
            if (it == this->mainNodeMap_.end())
            {
                return false;
            }

            value = it->second->getValue();
            shouldTransform = modNodeAccess(it->second);
            return true;
        }

        bool checkGhost(const Key &key)
        {
            auto it = this->ghostNodeMap_.find(key);
            if (it == this->ghostNodeMap_.end())
            {
                return false;
            }

            this->delListNode(it->second);
            this->ghostNodeMap_.erase(it);
            return true;
        }

        // 没有变动淘汰队列容量
        void increaseCapacity()
        {
            ++this->capacity_;
        }

        bool decreaseCapacity()
        {
            if (this->capacity_ <= 0)
            {
                return false;
            }

            if (this->mainNodeMap_.size() == this->capacity_)
            {
                this->evictMainLruNode();
            }
            --this->capacity_;
            return true;
        }

    private:
        void initNodeLists()
        {
            this->mainDummyHead_ = std::make_shared<NodeType>();
            this->mainDummyTail_ = std::make_shared<NodeType>();
            this->mainDummyHead_->next_ = this->mainDummyTail_;
            this->mainDummyTail_->prev_ = this->mainDummyHead_;

            ghostDummyHead_ = std::make_shared<NodeType>();
            ghostDummyTail_ = std::make_shared<NodeType>();
            this->ghostDummyHead_->next_ = this->ghostDummyTail_;
            this->ghostDummyTail_->prev_ = this->ghostDummyHead_;
        }

        bool addMainNode(const Key &key, const Value &value)
        {
            if (this->mainNodeMap_.size() >= this->capacity_)
            {
                this->evictMainLruNode(); // 驱逐最近最少访问
            }

            NodePtr newNode = std::make_shared<NodeType>(key, value);
            this->addMainListNode(newNode);
            this->mainNodeMap_[key] = newNode;
            return true;
        }

        void evictMainLruNode()
        {
            NodePtr lruNode = this->mainDummyHead_->next_;
            if (lruNode == this->mainDummyTail_)
            {
                return;
            }

            // 从主链表中移除
            this->delListNode(lruNode);
            // 从主缓存映射中移除
            this->mainNodeMap_.erase(lruNode->getKey());

            // 添加到幽灵缓存
            if (this->ghostNodeMap_.size() >= this->ghostCapacity_)
            {
                this->evictGhostOldestNode();
            }
            this->addGhostNode(lruNode);
        }

        void delListNode(NodePtr node)
        {
            node->prev_->next_ = node->next_;
            node->next_->prev_ = node->prev_;
        }

        void evictGhostOldestNode()
        {
            NodePtr oldestNode = this->ghostDummyHead_->next_;
            if (oldestNode == this->ghostDummyTail_)
            {
                return;
            }

            this->delListNode(oldestNode);
            this->ghostNodeMap_.erase(oldestNode->getKey());
        }

        void addGhostNode(NodePtr node)
        {
            // 重置节点的访问计数
            node->accessCount_ = 1;

            // 添加到幽灵缓存的尾部
            this->addGhostListNode(node);
            // 添加到幽灵缓存映射
            this->ghostNodeMap_[node->getKey()] = node;
        }

        void addGhostListNode(NodePtr node)
        {
            node->prev_ = this->ghostDummyTail_->prev_;
            node->next_ = this->ghostDummyTail_;

            this->ghostDummyTail_->prev_->next_ = node; // 这里不能改顺序
            this->ghostDummyTail_->prev_ = node;
        }

        void addMainListNode(NodePtr node)
        {
            node->prev_ = this->mainDummyTail_->prev_;
            node->next_ = this->mainDummyTail_;

            this->mainDummyTail_->prev_->next_ = node; // 这里不能改顺序
            this->mainDummyTail_->prev_ = node;
        }

        bool modMainNode(NodePtr node, const Value &value)
        {
            node->setValue(value);
            this->moveMainMruNode(node);
            return true;
        }

        void moveMainMruNode(NodePtr node)
        {
            // 先从当前位置移除
            this->delListNode(node);
            // 添加到尾部
            this->addMainListNode(node);
        }

        bool modNodeAccess(NodePtr node)
        {
            this->moveMainMruNode(node);
            node->incrementAccessCount();
            return node->getAccessCount() >= this->transformThreshold_;
        }

    private:
        size_t capacity_;
        size_t ghostCapacity_;
        size_t transformThreshold_; // 转换门槛值

        // 主链表
        NodePtr mainDummyHead_;
        NodePtr mainDummyTail_;
        // 淘汰链表
        NodePtr ghostDummyHead_;
        NodePtr ghostDummyTail_;

        NodeMap mainNodeMap_; // key -> ArcNode
        NodeMap ghostNodeMap_;

        std::mutex mutex_;
    };
} // namespace CachePool

#endif // ARC_LRU_PART_HPP